﻿using System;
using System.Runtime.Serialization;
using ElectronicCommerce.Framework.Configuration.Entities;
using ElectronicCommerce.Framework.ExceptionManagement.Interface;

namespace ElectronicCommerce.Framework.ExceptionManagement.ExHandler
{
    [Serializable]
    public class CommEx : Exception
    {
        //带错误提示消息构造
        /// <summary>
        /// Initializes a new instance of the <see cref="CommEx"/> class.
        /// </summary>
        /// <param name="message">The message.</param>
        public CommEx(string message) : base(message) { }

        /// <summary>
        /// Initializes a new instance of the <see cref="CommEx"/> class.
        /// </summary>
        /// <param name="message">The message.</param>
        /// <param name="e">The e.</param>
        public CommEx(string message, Exception e) : base(message, e) { }

        // 反序列化
        /// <summary>
        /// Initializes a new instance of the <see cref="CommEx"/> class.
        /// </summary>
        /// <param name="info">The <see cref="T:System.Runtime.Serialization.SerializationInfo"/> that holds the serialized object data about the exception being thrown.</param>
        /// <param name="context">The <see cref="T:System.Runtime.Serialization.StreamingContext"/> that contains contextual information about the source or destination.</param>
        /// <exception cref="T:System.ArgumentNullException">The <paramref name="info"/> parameter is null. </exception>
        /// <exception cref="T:System.Runtime.Serialization.SerializationException">The class name is null or <see cref="P:System.Exception.HResult"/> is zero (0). </exception>
        protected CommEx(SerializationInfo info, StreamingContext context) : base(info, context) { }
    }

    /// <summary>
    /// 缺省异常处理器类
    /// </summary>
    public class DefaultExHandler : ExHandlerBase
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="DefaultExHandler"/> class.
        /// </summary>
        public DefaultExHandler()
            : base()
        {

        }

        /// <summary>
        /// 进行截取过滤以获取错误代码行
        /// </summary>
        /// <param name="e">系统异常</param>
        /// <returns>代码行位置信息</returns>
        private string GetExceptionLocation(System.Exception e)
        {
            //int iLen, iReturnPos;
            //string strErr, sLocateTemp, sLocate = "";

            ////获取源异常信息
            //strErr = e.StackTrace;

            //if (strErr != string.Empty && strErr != null)
            //{
            //    iLen = strErr.Length;

            //    //查找第一行，其中行以回车结束
            //    iReturnPos = strErr.IndexOf("\r\n", 0, iLen);
            //    while (iReturnPos > 0 && strErr.Length > 1)
            //    {
            //        //判断当前读取的行中有无 line 字样 ， 表示出错的具体代码行
            //        sLocateTemp = strErr.Substring(0, iReturnPos);
            //        if (sLocateTemp.IndexOf("line", 0, sLocateTemp.Length) > 0)
            //        {
            //            sLocate += sLocateTemp + Environment.NewLine;
            //            return sLocate.Trim();
            //        }

            //        //将已判断的行删除，取下一行数据，加4表示/r/n四位
            //        strErr = strErr.Substring(iReturnPos + 4, iLen - iReturnPos - 4);
            //        iLen = strErr.Length;
            //        iReturnPos = strErr.IndexOf("\r\n", 0, iLen);
            //    }

            //    if (strErr.IndexOf("line", 0, strErr.Length) > 0)
            //        sLocate += strErr + Environment.NewLine;
            //}
            //return sLocate.Trim().Replace("\r\n", "\\r\\n");

            return e.ToString();
        }

        /// <summary>
        /// 调用所有的异常记录对象进行异常信息记录
        /// </summary>
        /// <param name="ex">The ex.</param>
        /// <param name="strUserId">The STR user id.</param>
        /// <param name="strErrorCode">The STR error code.</param>
        /// <param name="strExtention">The STR extention.</param>
        private void LogEx(Exception ex, string strUserId, string strErrorCode, string strErrorMessage, string pageAlias, params string[] strExtention)
        {
            foreach (IExLogHandler exLogHandler in lstLogHandler)
            {
                exLogHandler.ExLog(ex, strErrorCode, strErrorMessage, pageAlias, m_ExHandlerConfig.Name, strUserId, strExtention);
            }
        }

        /// <summary>
        /// 实现接口IExLogHandler中的ProcessExeception方法，提供异常处理的方法
        /// </summary>
        /// <param name="ex">The ex.</param>
        /// <param name="strUserId">The STR user id.</param>
        /// <param name="strErrorCode">The STR error code.</param>
        /// <param name="strExtention">The STR extention.</param>
        /// <returns></returns>
        public override string ProcessExeception(Exception ex, string strUserId, string strErrorCode, string strErrorMessage, string pageAlias, out MessageBoxType messageType, params string[] strExtention)
        {
            // 判断处理的异常是否是已经被处理过的异常，避免重复处理
            bool IsNewException = ex.GetType() != Type.GetType("ElectronicCommerce.Framework.ExceptionManagement.ExHandler.CommEx, ElectronicCommerce.Framework");

            // 若不是调试编译时，则记录日志信息到数据库；若是则不记录

            // 若是还未处理过的异常
            if (IsNewException)
            {
                // 记录异常信息
                LogEx(ex, strUserId, strErrorCode, strErrorMessage, pageAlias, strExtention);
            }

            ExReturnMode returnMode = (ExReturnMode)Enum.Parse(typeof(ExReturnMode), m_ExHandlerConfig.ReturnMode, true);
            // 根据配置中的异常返回方式，决定处理方式
            switch (returnMode)
            {
                // 返回类型为错误编码
                case ExReturnMode.ErrorCode:
                    {
                        messageType = MessageBoxType.Redirect;
                        return strErrorCode;
                    }
                // 返回类型为详细错误信息（友好提示）
                case ExReturnMode.ErrorString:
                    {
                        messageType = MessageBoxType.Error;
                        // 若不是调试编译时，返回带异常记录ID的友好提示信息
                        // 否则，返回Exception.Message和异常定位信息

                        if (string.IsNullOrEmpty(strErrorMessage))
                        {
                            string stackTrace = GetExceptionLocation(ex);
                            stackTrace = stackTrace.Substring(3).Replace("\\", "\\\\");
                            string errorMsg = string.Format("{0} 发生异常.\\r\\n错误编号:{1}.\\r\\n错误信息:\\r\\n{2}\\r\\n错误出在:\\r\\n{3}",
                                m_ExHandlerConfig.Name, strErrorCode, ex.Message.Replace(Environment.NewLine, "\\r\\n"), stackTrace);
                            if (IsNewException)
                            {
                                return errorMsg;
                            }
                            else
                            {
                                return ex.Message;
                            }
                        }
                        else
                        {
                            string stackTrace = GetExceptionLocation(ex);
                            stackTrace = stackTrace.Substring(3).Replace("\\", "\\\\");
                            string errorMsg = string.Format("{0} 发生异常.\\r\\n错误编号:{1}.\\r\\n错误信息:\\r\\n{2}\\r\\n错误出在:\\r\\n{3}",
                                m_ExHandlerConfig.Name, strErrorCode, ex.Message.Replace(Environment.NewLine, "\\r\\n"), strErrorMessage);
                            if (IsNewException)
                            {
                                return errorMsg;
                            }
                            else
                            {
                                return ex.Message;
                            }
                        }
                    }
                // 返回类型为详细异常信息（Exception.Message）
                case ExReturnMode.ExceptionString:
                    {
                        messageType = MessageBoxType.Error;
                        return ex.Message;
                    }

                // 将异常向上抛出
                case ExReturnMode.Exception:
                    {
                        // 如果是该层自身引发的异常则包装后抛出
                        if (IsNewException)
                        {
                            // 若是非调试编译环境，即是Remoting分布式环境中，无法抛出带有异常定位信息的Exceptiong对象，把异常Message用自定义的异常类包装后抛出
                            // 若是调试编译环境，则是非非分布式环境中，可以用自定义异常信息把原异常对象整个包装后抛出（包含异常定位信息等）

                            if (string.IsNullOrEmpty(strErrorMessage))
                            {
                                string stackTrace = GetExceptionLocation(ex);
                                stackTrace = stackTrace.Replace("\\", "\\\\");
                                throw new CommEx(string.Format("{0} 发生异常.\\r\\n错误编号:{1}.\\r\\n错误信息:\\r\\n{2}\\r\\n错误出在:\\r\\n{3}",
                                    m_ExHandlerConfig.Name, strErrorCode, ex.Message, stackTrace), ex);
                            }
                            else
                            {
                                throw new CommEx(strErrorMessage);
                            }
                        }
                        // 若是捕捉到的是包装后的异常（即上层抛出的）
                        else
                        {
                            throw ex;
                        }
                    }
                default:
                    {
                        messageType = MessageBoxType.Error;
                        return null;
                    }
            }
        }
    }
}
